package main

import (
	"fmt"

	"math"
	"strconv"
)

type DrNumArray struct {
	ISequence
	DrAbstractObject
	data []float64
	dims []int
	// rowCount   int
	// colCount   int
	layerCount int
	timeCount  int
	cursor     int
}

func (self *DrNumArray) Next() IObject {
	if self.cursor == self.Len() {
		return nil
	}
	result := self.data[self.cursor]
	self.cursor += 1
	return NewNum(result)
}

func (self *DrNumArray) ResetCursor() {
	self.cursor = 0
}

func (self *DrNumArray) getType() DataType {
	return self.Type
}
func (self *DrNumArray) getValue() float64 {
	panic("Only used for simple object such as int and float")
}
func (self *DrNumArray) initMethods() {
	self.members = make(map[string]IObject)
	self.members["reshape"] = NewFunction("reshape", []string{"rowCount", "colCount"})
	self.members["pearsonr"] = NewFunction("pearsonr", []string{"arr1", "arr2"})
}
func NewNumArray1d(count int) *DrNumArray {
	mat := new(DrNumArray)
	mat.data = make([]float64, count, count)
	for i := 0; i < count; i++ {
		mat.data[i] = 0
	}
	mat.Type = TypeNumArray
	mat.dims = append(mat.dims, count)
	mat.initMethods()
	return mat
}
func NewNumArray2d(rows, cols int) *DrNumArray {
	var mat *DrNumArray
	mat = new(DrNumArray)
	if rows < 1 {
		rows = 1
	}
	mat.data = make([]float64, rows*cols, rows*cols)
	if rows <= 1 {
		mat.dims = append(mat.dims, cols)
	} else {
		mat.dims = append(mat.dims, rows, cols)
	}
	for i := 0; i < rows*cols; i++ {
		mat.data[i] = 0
	}
	mat.Type = TypeNumArray
	mat.initMethods()
	return mat
}
func NewNumArray3d(times, rows, cols int) *DrNumArray {
	var mat *DrNumArray
	mat = new(DrNumArray)
	n := times * rows * cols
	mat.data = make([]float64, n, n)
	mat.dims = append(mat.dims, times, rows, cols)
	for i := 0; i < n; i++ {
		mat.data[i] = 0
	}
	mat.Type = TypeNumArray
	mat.initMethods()
	return mat
}
func NewNumArray4d(times, layers, rows, cols int) *DrNumArray {
	var mat *DrNumArray
	mat = new(DrNumArray)
	n := times * layers * rows * cols
	mat.data = make([]float64, n, n)
	mat.dims = append(mat.dims, times, layers, rows, cols)
	for i := 0; i < n; i++ {
		mat.data[i] = 0
	}
	mat.Type = TypeNumArray
	mat.initMethods()
	return mat
}
func NewNumArray1(obs []IObject) *DrNumArray {
	var mat *DrNumArray
	mat = new(DrNumArray)
	cols := len(obs)
	mat.data = make([]float64, cols, cols)

	mat.dims = append(mat.dims, cols)
	for i := 0; i < cols; i++ {
		v := obs[i].getDouble()
		mat.data[i] = v
	}
	mat.Type = TypeNumArray
	mat.initMethods()
	return mat
}
func CreateArrayFromParam(params []IObject) *DrNumArray {
	if len(params) > 1 {
		panic("not support multiple parameter objects")
	}
	seq, ok := params[0].(IObSequence)
	dims := make([]int, 0, 4)
	result := new(DrNumArray)
	result.Type = TypeNumArray
	if ok {
		dims = append(dims, seq.Len())
		if seq.Len() > 0 {
			seq1, ok1 := seq.GetElems()[0].(IObSequence) //如序列中的第一个元素不是序列，说明这只是一个一维的
			if !ok1 {
				arr := NewNumArray1(seq.GetElems())
				arr.initMethods()
				return arr
			}
			//有二维以上
			if seq1.Len() > 0 {
				seq2, ok2 := seq1.GetElems()[0].(IObSequence) //如序列中的第一个元素不是序列，说明这只是一个一维向量
				if !ok2 {                                     //确定只能算二维序列
					for i := 0; i < seq.Len(); i++ {
						seq_1 := seq.GetElems()[i].(IObSequence)
						arr := NewNumArray1(seq_1.GetElems())
						result.data = append(result.data, arr.data...)
					}
					result.dims = make([]int, 0, 2)
					result.dims = append(result.dims, seq.Len(), seq1.Len())
					result.initMethods()
					return result
				}
				//有三维以上
				if seq2.Len() > 0 {
					seq3, ok3 := seq2.GetElems()[0].(IObSequence) //如序列中的第一个元素不是序列，说明这只是一个一维向量
					if !ok3 {
						//确定只能算三维序列
						for i := 0; i < seq.Len(); i++ {
							seq_1 := seq.GetElems()[i].(IObSequence)
							for j := 0; j < seq_1.Len(); j++ {
								seq_2 := seq_1.GetElems()[j].(IObSequence)
								arr := NewNumArray1(seq_2.GetElems())
								result.data = append(result.data, arr.data...)
							}
						}

						result.dims = make([]int, 0, 3)
						result.dims = append(result.dims, seq.Len(), seq1.Len(), seq2.Len())
						result.initMethods()
						return result
					}
					if seq3.Len() > 0 {
						_, ok4 := seq3.GetElems()[0].(IObSequence) //如序列中的第一个元素不是序列，说明这只是一个一维向量
						if !ok4 {
							//确定只能算四维序列
							for i := 0; i < seq.Len(); i++ {
								seq_1 := seq.GetElems()[i].(IObSequence)
								for j := 0; j < seq_1.Len(); j++ {
									seq_2 := seq_1.GetElems()[j].(IObSequence)
									for k := 0; k < seq_2.Len(); k++ {
										seq_3 := seq_2.GetElems()[j].(IObSequence)
										arr := NewNumArray1(seq_3.GetElems())
										result.data = append(result.data, arr.data...)
									}
								}
							}
							// result.timeCount = seq.Len()
							// result.layerCount = seq1.Len()
							// result.rowCount = seq2.Len()
							// result.colCount = seq3.Len()
							result.dims = make([]int, 0, 4)
							result.dims = append(result.dims, seq.Len(), seq1.Len(), seq2.Len(), seq3.Len())
							result.initMethods()
							return result
						}
					}
					panic("dimensions cannot exceed 4")
				}
			}
		}
	}
	iter, ok1 := params[0].(IIterable)
	if ok1 {
		iter.ResetCursor()
		arr := NewNumArray1d(0)
		for {
			v := iter.Next()
			if v == nil {
				break
			}
			arr.data = append(arr.data, v.getDouble())
		}
		arr.dims = []int{len(arr.data)}
		arr.initMethods()
		return arr
	}
	panic("not implemented")

}
func (self *DrNumArray) Copy() *DrNumArray {
	result := new(DrNumArray)
	result.dims = append(result.dims, self.dims...)
	result.data = append(result.data, self.data...)
	result.members = self.members
	result.Type = self.Type
	return result
}
func (self *DrNumArray) Print(interp *Interpreter) {
	fmt.Print(self.AsString())
}
func (self *DrNumArray) AsString() string {
	if len(self.dims) == 1 {
		n := len(self.data)
		if n < 10 {
			temp := "array ["
			for i := 0; i < n; i++ {
				temp += strconv.FormatFloat(self.data[i], 'f', 4, 64) + " "
			}
			temp += "]"
			return temp
		} else {
			rangeR := []int{0, 1, 2, 3, 4, 5, n - 5, n - 4, n - 3, n - 2, n - 1}
			temp := "array ["
			for _, i := range rangeR {
				if i == 5 {
					temp += "... "
					continue
				}
				temp += strconv.FormatFloat(self.data[i], 'f', 4, 64) + " "
			}

			temp += "]"
			return temp
		}
	} else if len(self.dims) == 2 {
		rows := self.dims[0]
		cols := self.dims[1]
		rangeR := []int{0, 1, 2, 3, 4, 5, rows - 5, rows - 4, rows - 3, rows - 2, rows - 1}
		rangeC := []int{0, 1, 2, 3, 4, 5, cols - 5, cols - 4, cols - 3, cols - 2, cols - 1}
		temp := "array ["
		if rows <= 10 {
			for row := 0; row < rows; row++ {
				temp += "["
				if cols <= 10 {
					for col := 0; col < cols; col++ {
						temp += strconv.FormatFloat(self.Get2dValue(row, col), 'f', 3, 64) + " "
					}
					temp += "]\n"
				} else {
					for _, col := range rangeC {
						if col == 5 {
							temp += "... "
							continue
						}
						temp += strconv.FormatFloat(self.Get2dValue(row, col), 'f', 3, 64) + " "

					}
					temp += "]\n"
				}
			}
			temp += "]"
			return temp
		} else {

			for _, row := range rangeR {
				if row == 5 {
					temp += "... \n"
					continue
				}
				if cols <= 10 {
					for col := 0; col < cols; col++ {
						temp += strconv.FormatFloat(self.Get2dValue(row, col), 'f', 3, 64) + " "
					}
					temp += "\n"
				} else {
					for _, col := range rangeC {
						if col == 5 {
							temp += "... "
							continue
						}
						temp += strconv.FormatFloat(self.Get2dValue(row, col), 'f', 3, 64) + " "
					}
					temp += "\n"
				}
			}
			temp += "]"
			return temp
		}
	}
	panic("not implemented")
}

func (self *DrNumArray) T() *DrNumArray {
	if len(self.dims) != 2 {
		panic("must be two dimensioned")
	}
	rowCount := self.dims[0]
	colCount := self.dims[1]
	mat := NewNumArray2d(rowCount, colCount)
	slice := mat.Data()
	data := self.Data()
	for row := 0; row < rowCount; row++ {
		for col := 0; col < colCount; col++ {
			slice[col][row] = data[row][col]
		}
	}

	return mat
}
func (self *DrNumArray) Multiply(x float64) *DrNumArray {
	mat := self.Copy()
	for i := 0; i < len(self.data); i++ {
		mat.data[i] *= x
	}
	return mat
}
func (self *DrNumArray) Add(x float64) *DrNumArray {
	mat := self.Copy()
	for i := 0; i < len(self.data); i++ {
		mat.data[i] += x
	}
	return mat
}
func (self *DrNumArray) MultiNum2d(arr *DrNumArray) *DrNumArray {
	for i, v := range self.dims {
		if v != arr.dims[i] {
			panic("the shapees of two arrays are not matched")
		}
	}
	mat := self.Copy()
	for i := 0; i < len(self.data); i++ {
		mat.data[i] *= arr.data[i]
	}
	return mat
}

//指用x除以本矩阵
func (self *DrNumArray) Reciprocal(x float64) *DrNumArray {
	mat := self.Copy()
	for i := 0; i < len(self.data); i++ {
		mat.data[i] = x / self.data[i]
	}
	return mat
}
func (self *DrNumArray) AddNum2d(arr *DrNumArray) IObject {
	if arr.Len() != self.Len() {
		panic("data must be in the same length")
	}
	mat := self.Copy()
	for i := 0; i < len(self.data); i++ {
		mat.data[i] += arr.data[i]
	}
	return mat
}
func (x *DrNumArray) PearsonR(y *DrNumArray) float64 {
	var xmean, ymean, xxmean, yymean, xymean float64
	n := x.Len()
	for i := 0; i < n; i++ {
		vx, vy := x.data[i], y.data[i]
		xmean += vx
		ymean += vy
		xxmean += vx * vx
		yymean += vy * vy
		xymean += vx * vy
	}
	upper := xymean - xmean*ymean/float64(n)
	lower := math.Sqrt((xxmean - xmean*xmean/float64(n)) * (yymean - ymean*ymean/float64(n)))
	return upper / lower
}
func (self *DrNumArray) DistEuclid(a *DrNumArray) float64 {
	var v float64
	for i := 0; i < len(self.data); i++ {
		x := self.data[i] - a.data[i]
		v += x * x
	}
	return math.Sqrt(v)
}
func (self *DrNumArray) Pow(x float64) *DrNumArray {
	mat := self.Copy()

	for i := 0; i < len(self.data); i++ {
		mat.data[i] = math.Pow(self.data[i], x)
	}
	return mat
}
func (self *DrNumArray) Exp() *DrNumArray {
	mat := self.Copy()
	for i := 0; i < len(self.data); i++ {
		mat.data[i] = math.Exp(self.data[i])
	}
	return mat
}
func (self *DrNumArray) Log() *DrNumArray {
	mat := self.Copy()
	for i := 0; i < len(self.data); i++ {
		mat.data[i] = math.Log(self.data[i])
	}
	return mat
}

//func (self *Num2d) Sqrt() *Num2d {
//	result := NewNum2d(self.colCount, self.rowCount)
//	for i := 0; i < self.rowCount*self.colCount; i++ {
//		result.data[i] = math.Sqrt(self.data[i])
//	}
//	return result

//}
func (self *DrNumArray) Sin() *DrNumArray {
	result := self.Copy()

	for i := 0; i < len(self.data); i++ {
		result.data[i] = math.Sin(self.data[i])
	}
	return result

}
func (self *DrNumArray) Cos() *DrNumArray {
	mat := self.Copy()
	for i := 0; i < len(self.data); i++ {
		mat.data[i] = math.Cos(self.data[i])
	}
	return mat
}
func (self *DrNumArray) Sqrt() *DrNumArray {
	mat := self.Copy()

	for i := 0; i < len(self.data); i++ {
		mat.data[i] = math.Tan(self.data[i])
	}
	return mat
}
func (self *DrNumArray) Asin() *DrNumArray {
	mat := self.Copy()
	for i := 0; i < len(self.data); i++ {
		mat.data[i] = math.Asin(self.data[i])
	}
	return mat
}
func (self *DrNumArray) Len() int {
	return len(self.data)
}
func (self *DrNumArray) Acos() *DrNumArray {
	result := self.Copy()
	mat := result
	for i := 0; i < len(self.data); i++ {
		mat.data[i] = math.Acos(self.data[i])
	}
	return result
}
func (self *DrNumArray) Atan() *DrNumArray {
	result := self.Copy()
	mat := result
	for i := 0; i < len(self.data); i++ {
		mat.data[i] = math.Atan(self.data[i])
	}
	return result
}
func (self *DrNumArray) Erf() *DrNumArray {
	result := self.Copy()
	mat := result
	for i := 0; i < len(self.data); i++ {
		mat.data[i] = math.Erf(self.data[i])
	}
	return result
}
func (self *DrNumArray) Gamma() *DrNumArray {
	result := self.Copy()
	mat := result
	for i := 0; i < len(self.data); i++ {
		mat.data[i] = math.Gamma(self.data[i])
	}
	return result
}
func (self *DrNumArray) Abs() *DrNumArray {
	result := self.Copy()
	mat := result
	for i := 0; i < len(self.data); i++ {
		mat.data[i] = math.Abs(self.data[i])
	}
	return result
}
func (self *DrNumArray) Max() float64 {
	v := -1e100
	for i := 0; i < len(self.data); i++ {
		if v < self.data[i] {
			v = self.data[i]
		}
	}
	return v
}
func (self *DrNumArray) Min() float64 {
	v := 1e100
	for i := 0; i < len(self.data); i++ {
		if v > self.data[i] {
			v = self.data[i]
		}
	}
	return v
}
func (self *DrNumArray) Data() [][]float64 {
	if len(self.dims) != 2 {
		panic("not implemented for other than two dimensions")
	}
	rowCount := self.dims[0]
	colCount := self.dims[1]
	var slice [][]float64
	slice = make([][]float64, rowCount, rowCount)
	for row := 0; row < rowCount; row++ {
		begin := row * colCount
		end := begin + colCount
		slice[row] = self.data[begin:end]
	}
	return slice
}
func (self *DrNumArray) Data1d() []float64 {
	return self.data
}
func (self *DrNumArray) Mean() float64 {
	sumv := 0.0
	n := self.Len()
	for i := 0; i < n; i++ {
		sumv += self.data[i]
	}
	return sumv / float64(n)
}
func (self *DrNumArray) Var() float64 {
	sumv := 0.0
	sumv2 := 0.0
	n := self.Len()
	for i := 0; i < n; i++ {
		sumv += self.data[i]
		sumv2 += self.data[i] * self.data[i]
	}
	mean := sumv / float64(n)
	mean2 := sumv2 / float64(n)
	return mean2 - mean*mean
}
func (self *DrNumArray) Std() float64 {
	return math.Sqrt(self.Var())
}
func (self *DrNumArray) Get1dValue(i int) float64 {
	return self.data[i]
}
func (self *DrNumArray) Get2dValue(row, col int) float64 {
	if len(self.dims) != 2 {
		panic("must be in two dimensions")
	}
	return self.data[row*self.dims[1]+col]
}
func (self *DrNumArray) Get3dValue(time, row, col int) float64 {
	if len(self.dims) != 3 {
		panic("must be in three dimensions")
	}
	return self.data[time*self.dims[1]*self.dims[2]+row*self.dims[2]+col]
}
func (self *DrNumArray) Get4dValue(time, layer, row, col int) float64 {
	if len(self.dims) != 3 {
		panic("must be in three dimensions")
	}
	return self.data[time*self.dims[1]*self.dims[2]*self.dims[3]+layer*self.dims[2]*self.dims[3]+row*self.dims[3]+col]
}
func (self *DrNumArray) GetItems(params []IObject) IObject {
	obj := params[0]
	if obj.getType() == TypePair {
		obP := obj.(*DrPair)
		start := obP.elem_A.getInt()
		if start < 0 {
			start += self.Len()
		}
		var end int
		if obP.elem_B == nil {
			end = self.Len()
		} else {
			end = obP.elem_B.getInt()
			if end < 0 {
				end += self.Len()
			}
		}
		elems := self.data[start:end]

		arr := NewNumArray2d(1, end-start)
		copy(arr.data, elems)
		return arr
	} else if obj.getType() == TypeInt || obj.getType() == TypeNum {
		index := params[0].getInt()
		if index < 0 {
			index += self.Len()
		}
		return NewNum(self.data[index])
	} else if obj.getType() == TypeTuple {
		tpOb := obj.(*DrTuple)
		n := tpOb.Len()
		if n == 2 {
			if len(self.dims) != 2 {
				panic("not in two dimensions:")
			}
			var dim0, dim1, start0, start1 int
			elem0 := tpOb.Elements[0]
			if elem0.getType() == TypePair {
				pair := elem0.(*DrPair)
				end0 := self.dims[0]
				if pair.elem_B != nil {
					end0 = pair.elem_B.getInt()
					if end0 < 0 {
						end0 += self.dims[0]
					}
				}
				dim0 = end0 - pair.elem_A.getInt()
				start0 = pair.elem_A.getInt()

			} else if elem0.getType() == TypeInt {
				dim0 = 1
				start0 = elem0.getInt()

			}
			elem1 := tpOb.Elements[1]
			if elem1.getType() == TypePair {
				pair := elem1.(*DrPair)
				end1 := self.dims[1]
				if pair.elem_B != nil {
					end1 = pair.elem_B.getInt()
					if end1 < 0 {
						end1 += self.dims[1]
					}
				}
				dim1 = end1 - pair.elem_A.getInt()
				start1 = pair.elem_A.getInt()

			} else if elem1.getType() == TypeInt {
				dim1 = 1
				start1 = elem1.getInt()

			}
			if start0 < 0 {
				start0 += self.dims[0]
			}
			if start1 < 0 {
				start1 += self.dims[1]
			}
			arr := NewNumArray2d(dim0, dim1)
			for row := 0; row < dim0; row++ {
				row_src := row + start0
				for col := 0; col < dim1; col++ {
					col_src := col + start1
					arr.Set2dValue(row, col, self.Get2dValue(row_src, col_src))
				}
			}
			return arr
		} else if n == 3 {
			if len(self.dims) != 3 {
				panic("not in 3 dimensions:")
			}
			var dim0, dim1, start0, start1 int
			elem0 := tpOb.Elements[0]
			if elem0.getType() == TypePair {
				pair := elem0.(*DrPair)
				end0 := self.dims[0]
				if pair.elem_B != nil {
					end0 = pair.elem_B.getInt()
					if end0 < 0 {
						end0 += self.dims[0]
					}
				}
				dim0 = end0 - pair.elem_A.getInt()
				start0 = pair.elem_A.getInt()
			} else if elem0.getType() == TypeInt {
				dim0 = 1
				start0 = elem0.getInt()
			}
			elem1 := tpOb.Elements[1]
			if elem1.getType() == TypePair {
				pair := elem1.(*DrPair)
				end1 := self.dims[1]
				if pair.elem_B != nil {
					end1 = pair.elem_B.getInt()
					if end1 < 0 {
						end1 += self.dims[1]
					}
				}
				dim1 = end1 - pair.elem_A.getInt()
				start1 = pair.elem_A.getInt()

			} else if elem1.getType() == TypeInt {
				dim1 = 1
				start1 = elem1.getInt()
			}
			var dim2, start2 int
			elem2 := tpOb.Elements[2]
			if elem2.getType() == TypePair {
				pair := elem2.(*DrPair)
				end2 := self.dims[2]
				if pair.elem_B != nil {
					end2 = pair.elem_B.getInt()
					if end2 < 0 {
						end2 += self.dims[2]
					}
				}
				dim2 = end2 - pair.elem_A.getInt()
				start2 = pair.elem_A.getInt()

			} else if elem2.getType() == TypeInt {
				dim2 = 1
				start2 = elem2.getInt()
			}
			if start0 < 0 {
				start0 += self.dims[0]
			}
			if start1 < 0 {
				start1 += self.dims[1]
			}
			if start2 < 0 {
				start2 += self.dims[2]
			}

			arr := NewNumArray3d(dim0, dim1, dim2)
			for time := 0; time < dim0; time++ {
				time_src := time + start0
				for row := 0; row < dim1; row++ {
					row_src := row + start1
					for col := 0; col < dim2; col++ {
						col_src := col + start2
						arr.Set3dValue(time, row, col, self.Get3dValue(time_src, row_src, col_src))
					}
				}
			}
			return arr

		} else if n == 4 {
			if len(self.dims) != 4 {
				panic("not in 4 dimensions:")
			}
			var dim0, dim1, start0, start1 int
			elem0 := tpOb.Elements[0]
			if elem0.getType() == TypePair {
				pair := elem0.(*DrPair)
				end0 := self.dims[0]
				if pair.elem_B != nil {
					end0 = pair.elem_B.getInt()
					if end0 < 0 {
						end0 += self.dims[0]
					}
				}
				dim0 = end0 - pair.elem_A.getInt()
				start0 = pair.elem_A.getInt()

			} else if elem0.getType() == TypeInt {
				dim0 = 1
				start0 = elem0.getInt()
			}
			elem1 := tpOb.Elements[1]
			if elem1.getType() == TypePair {
				pair := elem1.(*DrPair)
				end1 := self.dims[1]
				if pair.elem_B != nil {
					end1 = pair.elem_B.getInt()
					if end1 < 0 {
						end1 += self.dims[1]
					}
				}
				dim1 = end1 - pair.elem_A.getInt()
				start1 = pair.elem_A.getInt()

			} else if elem1.getType() == TypeInt {
				dim1 = 1
				start1 = elem1.getInt()
			}
			var dim2, start2 int
			elem2 := tpOb.Elements[2]
			if elem2.getType() == TypePair {
				pair := elem2.(*DrPair)
				end2 := self.dims[2]
				if pair.elem_B != nil {
					end2 = pair.elem_B.getInt()
					if end2 < 0 {
						end2 += self.dims[2]
					}
				}
				dim2 = end2 - pair.elem_A.getInt()
				start2 = pair.elem_A.getInt()

			} else if elem2.getType() == TypeInt {
				dim2 = 1
				start2 = elem2.getInt()
			}
			var dim3, start3 int
			elem3 := tpOb.Elements[3]
			if elem3.getType() == TypePair {
				pair := elem3.(*DrPair)
				end3 := self.dims[3]
				if pair.elem_B != nil {
					end3 = pair.elem_B.getInt()
					if end3 < 0 {
						end3 += self.dims[3]
					}
				}
				dim3 = end3 - pair.elem_A.getInt()
				start3 = pair.elem_A.getInt()

			} else if elem3.getType() == TypeInt {
				dim3 = 1
				start3 = elem3.getInt()
			}
			if start0 < 0 {
				start0 += self.dims[0]
			}
			if start1 < 0 {
				start1 += self.dims[1]
			}
			if start2 < 0 {
				start2 += self.dims[2]
			}
			if start3 < 0 {
				start3 += self.dims[3]
			}

			arr := NewNumArray4d(dim0, dim1, dim2, dim3)
			for time := 0; time < dim0; time++ {
				time_src := time + start0
				for layer := 0; layer < dim1; layer++ {
					layer_src := layer + start1
					for row := 0; row < dim2; row++ {
						row_src := row + start2
						for col := 0; col < dim3; col++ {
							col_src := col + start3
							arr.Set4dValue(time, layer, row, col, self.Get4dValue(time_src, layer_src, row_src, col_src))
						}
					}
				}
			}
			return arr

		}
		panic("需要完善")
	}
	return NewNum(0)

}
func (self *DrNumArray) SetItems(params IObject, ob IObject) {
	if ob.getType() != TypeNum && ob.getType() != TypeInt {
		fmt.Println(ob.getType())
		panic("must be a number")
	}
	value := ob.getDouble()
	obj := params
	if obj.getType() == TypePair {
		obP := obj.(*DrPair)
		start := int(obP.elem_A.getDouble())
		var end int
		if obP.elem_B == nil {
			end = self.Len()
		} else {
			end = obP.elem_B.getInt()
			if end < 0 {
				end += self.Len()
			}
		}
		for i := start; i < end; i++ {
			self.data[i] = value
		}
		return
	} else if obj.getType() == TypeInt || obj.getType() == TypeNum {
		index := params.getInt()
		if index < 0 {
			index += self.Len()
		}
		self.data[index] = value
	} else if obj.getType() == TypeTuple {
		tpOb := obj.(*DrTuple)
		n := tpOb.Len()
		if n == 2 {
			if len(self.dims) != 2 {
				panic("not in two dimensions:")
			}
			var dim0, dim1, start0, start1 int
			elem0 := tpOb.Elements[0]
			if elem0.getType() == TypePair {
				pair := elem0.(*DrPair)
				end0 := self.dims[0]
				if pair.elem_B != nil {
					end0 = pair.elem_B.getInt()
					if end0 < 0 {
						end0 += self.dims[0]
					}
				}
				dim0 = end0 - pair.elem_A.getInt()
				start0 = pair.elem_A.getInt()
			} else if elem0.getType() == TypeInt {
				dim0 = 1
				start0 = elem0.getInt()
			}
			elem1 := tpOb.Elements[1]
			if elem1.getType() == TypePair {
				pair := elem1.(*DrPair)
				end1 := self.dims[1]
				if pair.elem_B != nil {
					end1 = pair.elem_B.getInt()
					if end1 < 0 {
						end1 += self.dims[1]
					}
				}
				dim1 = end1 - pair.elem_A.getInt()
				start1 = pair.elem_A.getInt()
			} else if elem1.getType() == TypeInt {
				dim1 = 1
				start1 = elem1.getInt()
			}
			if start0 < 0 {
				start0 += self.dims[0]
			}
			if start1 < 0 {
				start1 += self.dims[1]
			}
			//arr := NewNumArray2d(dim0, dim1)
			for row := 0; row < dim0; row++ {
				row_src := row + start0
				for col := 0; col < dim1; col++ {
					col_src := col + start1
					self.Set2dValue(row_src, col_src, value)
				}
			}
			return
		} else if n == 3 {
			if len(self.dims) != 3 {
				panic("not in 3 dimensions:")
			}
			var dim0, dim1, start0, start1 int
			elem0 := tpOb.Elements[0]
			if elem0.getType() == TypePair {
				pair := elem0.(*DrPair)
				end0 := self.dims[0]
				if pair.elem_B != nil {
					end0 = pair.elem_B.getInt()
					if end0 < 0 {
						end0 += self.dims[0]
					}
				}
				dim0 = end0 - pair.elem_A.getInt()
				start0 = pair.elem_A.getInt()
			} else if elem0.getType() == TypeInt {
				dim0 = 1
				start0 = elem0.getInt()
			}
			elem1 := tpOb.Elements[1]
			if elem1.getType() == TypePair {
				pair := elem1.(*DrPair)
				end1 := self.dims[1]
				if pair.elem_B != nil {
					end1 = pair.elem_B.getInt()
					if end1 < 0 {
						end1 += self.dims[1]
					}
				}
				dim1 = end1 - pair.elem_A.getInt()
				start1 = pair.elem_A.getInt()
			} else if elem1.getType() == TypeInt {
				dim1 = 1
				start1 = elem1.getInt()
			}
			var dim2, start2 int
			elem2 := tpOb.Elements[2]
			if elem2.getType() == TypePair {
				pair := elem2.(*DrPair)
				end2 := self.dims[2]
				if pair.elem_B != nil {
					end2 = pair.elem_B.getInt()
					if end2 < 0 {
						end2 += self.dims[2]
					}
				}
				dim2 = end2 - pair.elem_A.getInt()
				start2 = pair.elem_A.getInt()
			} else if elem2.getType() == TypeInt {
				dim2 = 1
				start2 = elem2.getInt()
			}
			if start0 < 0 {
				start0 += self.dims[0]
			}
			if start1 < 0 {
				start1 += self.dims[1]
			}
			if start2 < 0 {
				start2 += self.dims[2]
			}
			//arr := NewNumArray3d(dim0, dim1, dim2)
			for time := 0; time < dim0; time++ {
				time_src := time + start0
				for row := 0; row < dim1; row++ {
					row_src := row + start1
					for col := 0; col < dim2; col++ {
						col_src := col + start2
						self.Set3dValue(time_src, row_src, col_src, value)
					}
				}
			}
			return

		} else if n == 4 {
			if len(self.dims) != 4 {
				panic("not in 4 dimensions:")
			}
			var dim0, dim1, start0, start1 int
			elem0 := tpOb.Elements[0]
			if elem0.getType() == TypePair {
				pair := elem0.(*DrPair)
				end0 := self.dims[0]
				if pair.elem_B != nil {
					end0 = pair.elem_B.getInt()
					if end0 < 0 {
						end0 += self.dims[0]
					}
				}
				dim0 = end0 - pair.elem_A.getInt()
				start0 = pair.elem_A.getInt()
			} else if elem0.getType() == TypeInt {
				dim0 = 1
				start0 = elem0.getInt()
			}
			elem1 := tpOb.Elements[1]
			if elem1.getType() == TypePair {
				pair := elem1.(*DrPair)
				end1 := self.dims[1]
				if pair.elem_B != nil {
					end1 = pair.elem_B.getInt()
					if end1 < 0 {
						end1 += self.dims[1]
					}
				}
				dim1 = end1 - pair.elem_A.getInt()
				start1 = pair.elem_A.getInt()
			} else if elem1.getType() == TypeInt {
				dim1 = 1
				start1 = elem1.getInt()
			}
			var dim2, start2 int
			elem2 := tpOb.Elements[2]
			if elem2.getType() == TypePair {
				pair := elem2.(*DrPair)
				end2 := self.dims[2]
				if pair.elem_B != nil {
					end2 = pair.elem_B.getInt()
					if end2 < 0 {
						end2 += self.dims[2]
					}
				}
				dim2 = end2 - pair.elem_A.getInt()
				start2 = pair.elem_A.getInt()
			} else if elem2.getType() == TypeInt {
				dim2 = 1
				start2 = elem2.getInt()
			}
			var dim3, start3 int
			elem3 := tpOb.Elements[3]
			if elem3.getType() == TypePair {
				pair := elem3.(*DrPair)
				end3 := self.dims[3]
				if pair.elem_B != nil {
					end3 = pair.elem_B.getInt()
					if end3 < 0 {
						end3 += self.dims[3]
					}
				}
				dim3 = end3 - pair.elem_A.getInt()
				start2 = pair.elem_A.getInt()
			} else if elem3.getType() == TypeInt {
				dim3 = 1
				start3 = elem3.getInt()
			}
			if start0 < 0 {
				start0 += self.dims[0]
			}
			if start1 < 0 {
				start1 += self.dims[1]
			}
			if start2 < 0 {
				start2 += self.dims[2]
			}
			if start3 < 0 {
				start3 += self.dims[3]
			}
			//arr := NewNumArray4d(dim0, dim1, dim2, dim3)
			for time := 0; time < dim0; time++ {
				time_src := time + start0
				for layer := 0; layer < dim1; layer++ {
					layer_src := layer + start1
					for row := 0; row < dim2; row++ {
						row_src := row + start2
						for col := 0; col < dim3; col++ {
							col_src := col + start3
							self.Set4dValue(time_src, layer_src, row_src, col_src, value)
						}
					}
				}
			}
			return

		}
		panic("需要完善")
	}
	return

}

func (self *DrNumArray) Set1dValue(i int, x float64) {
	self.data[i] = x
}
func (self *DrNumArray) Set2dValue(row, col int, x float64) {
	if len(self.dims) != 2 {
		panic("must be in two dimensions")
	}
	self.data[row*self.dims[1]+col] = x
}
func (self *DrNumArray) Set3dValue(time, row, col int, x float64) {
	if len(self.dims) != 2 {
		panic("must be in two dimensions")
	}
	self.data[time*self.dims[1]*self.dims[2]+row*self.dims[2]+col] = x
}
func (self *DrNumArray) Set4dValue(time, layer, row, col int, x float64) {
	if len(self.dims) != 2 {
		panic("must be in two dimensions")
	}
	self.data[time*self.dims[1]*self.dims[2]*self.dims[3]+layer*self.dims[2]*self.dims[3]+row*self.dims[3]+col] = x
}
func FromSlice(data [][]float64) *DrNumArray {
	rows, cols := len(data), len(data[0])
	ob := NewNumArray2d(rows, cols)
	result := ob
	for row := 0; row < rows; row++ {
		for col := 0; col < cols; col++ {
			result.Set2dValue(row, col, data[row][col])
		}
	}
	return ob
}

func (self *DrNumArray) Reshape(rowCount, colCount int) *DrNumArray {
	if self.Len() != rowCount*colCount {
		panic("The dimensions must match")
	}
	result := self.Copy()
	if rowCount == 0 {
		result.dims = make([]int, 1, 1)
		result.dims[0] = colCount
	} else {
		result.dims = make([]int, 2, 2)
		result.dims[0] = rowCount
		result.dims[1] = colCount
	}
	return result
}

func (self *DrNumArray) executeMethod(funcName string, prams []IObject) IObject {

	if funcName == "reshape" {
		if len(prams) == 2 {
			return self.Reshape(1, prams[1].getInt())
		} else if len(prams) == 3 {
			return self.Reshape(prams[1].getInt(), prams[2].getInt())
		}
		panic("not implemented")
	}
	if funcName == "pearsonr" {
		return NewNum(self.PearsonR(prams[1].(*DrNumArray)))
	}
	if funcName == "distEuclid" {
		return NewNum(self.DistEuclid(prams[1].(*DrNumArray)))
	}
	if funcName == "dot" {
		panic("not implemented")
	}
	if funcName == "var" {
		return NewNum(self.Var())
	}
	if funcName == "std" {
		return NewNum(self.Std())
	}
	if funcName == "mean" {
		return NewNum(self.Mean())
	}
	panic("funcName is inexist for this object")

}
func (self *DrNumArray) getMembers() map[string]IObject {
	return self.members
}
